//////////////////////////////////////////////
// Buffer.js
//
//////////////////////////////////////////////

/// Class ------------------------------------

nkMemoryTests.Buffer = class Buffer extends nkDebug.TestClass
{
	// Statics
	static instance = new Buffer ("nkMemoryTests.containers") ;

	// Utils
	getBufferConstructor (managed)
	{
		return managed ? nkMemory.Buffer : nkMemory.unmanaged.Buffer ;
	}

	// Constructors
	testDefaultConstructor (managed)
	{
		const ctor = Buffer.instance.getBufferConstructor(managed) ;
		const b = new ctor () ;

		nkDebug.TestUtils.check(b.getSize() == 0) ;

		if (!managed)
			b.delete() ;
	}

	testCopyConstructor (managed0, managed1)
	{
		const ctor0 = Buffer.instance.getBufferConstructor(managed0) ;
		const b0 = new ctor0 (new Uint8Array ([1, 2, 3])) ;

		const ctor1 = Buffer.instance.getBufferConstructor(managed1) ;
		const b1 = new ctor1 (b0) ;

		nkDebug.TestUtils.check(b0.getSize() == b1.getSize(), "Wrong copy size") ;

		for (let i = 0 ; i < b0.getSize() ; ++i)
		{
			nkDebug.TestUtils.check(b0.getData()[i] == b1.getData()[i], "Wrong copy value") ;
			b0.getData()[i] = -1 ;
			nkDebug.TestUtils.check(b0.getData()[i] != b1.getData()[i], "Data actually not copied") ;
		}

		if (!managed0)
			b0.delete() ;

		if (!managed1)
			b1.delete() ;
	}

	testSizeConstructor (managed)
	{
		const ctor = Buffer.instance.getBufferConstructor(managed) ;
		const b = new ctor (40) ;

		nkDebug.TestUtils.check(b.getSize() == 40, "Wrong size") ;

		if (!managed)
			b.delete() ;
	}

	testArrayBufferConstructor (managed)
	{
		const a = new ArrayBuffer (5) ;
		const v = new Uint8Array (a) ;
		v[0] = 1 ;
		v[1] = 2 ;
		v[2] = 3 ;
		v[3] = 4 ;
		v[4] = 5 ;

		const ctor = Buffer.instance.getBufferConstructor(managed) ;
		const b = new ctor (a) ;

		nkDebug.TestUtils.check(b.getSize() == a.byteLength, "Bad length") ;

		for (let i = 0 ; i < 5 ; ++i)
			nkDebug.TestUtils.check(b.getData()[i] == v[i], "Bad copy") ;

		if (!managed)
			b.delete() ;
	}

	testTypedConstructor (managed, typedConstructor)
	{
		const a = new typedConstructor ([1, 2, 3, 4, 5]) ;
		const ctor = Buffer.instance.getBufferConstructor(managed) ;
		const b = new ctor (a) ;

		nkDebug.TestUtils.check(b.getSize() == a.byteLength, "Bad length") ;

		// Check copy only for types aligning on 1 byte too
		if (a.BYTES_PER_ELEMENT == 1)
		{
			for (let i = 0 ; i < 5 ; ++i)
				nkDebug.TestUtils.check(b.getData()[i] == a[i], "Bad copy") ;
		}

		if (!managed)
			b.delete() ;
	}

	testInt8ArrayConstructor (managed) {Buffer.instance.testTypedConstructor(managed, Int8Array) ;}
	testUint8ArrayConstructor (managed) {Buffer.instance.testTypedConstructor(managed, Uint8Array) ;}
	testUint8ClampedArrayConstructor (managed) {Buffer.instance.testTypedConstructor(managed, Uint8ClampedArray) ;}
	testInt16ArrayConstructor (managed) {Buffer.instance.testTypedConstructor(managed, Int16Array) ;}
	testUint16ArrayConstructor (managed) {Buffer.instance.testTypedConstructor(managed, Uint16Array) ;}
	testInt32ArrayConstructor (managed) {Buffer.instance.testTypedConstructor(managed, Int32Array) ;}
	testUint32ArrayConstructor (managed) {Buffer.instance.testTypedConstructor(managed, Uint32Array) ;}
	testFloat32ArrayConstructor (managed) {Buffer.instance.testTypedConstructor(managed, Float32Array) ;}
	testFloat64ArrayConstructor (managed) {Buffer.instance.testTypedConstructor(managed, Float64Array) ;}

	testBigTypedConstructor (managed, typedConstructor)
	{
		const a = new typedConstructor ([1n, 2n, 3n, 4n, 5n]) ;
		const ctor = Buffer.instance.getBufferConstructor(managed) ;
		const b = new ctor (a) ;

		nkDebug.TestUtils.check(b.getSize() == a.byteLength, "Bad length") ;

		if (!managed)
			b.delete() ;
	}

	testBigInt64ArrayConstructor (managed) {Buffer.instance.testBigTypedConstructor(managed, BigInt64Array) ;}
	testBigUint64ArrayConstructor (managed) {Buffer.instance.testBigTypedConstructor(managed, BigUint64Array) ;}

	testArrayBufferConstructorProperCopy (managed)
	{
		const a = new ArrayBuffer (2) ;
		const v = new Uint8Array (a) ;
		v[0] = 1 ;
		v[1] = 2 ;

		const ctor = Buffer.instance.getBufferConstructor(managed) ;
		const b = new ctor (a) ;

		v[0] = 5 ;
		nkDebug.TestUtils.check(b.getData()[0] != v[0], "Entry is shared") ;

		if (!managed)
			b.delete() ;
	}

	testTypedConstructorProperCopy (managed, typedConstructor)
	{
		const a = new typedConstructor ([1, 2]) ;
		const ctor = Buffer.instance.getBufferConstructor(managed) ;
		const b = new ctor (a) ;

		const v = new Uint8Array (a.buffer) ;
		v[0] = 5 ;
		nkDebug.TestUtils.check(b.getData()[0] != v[0]) ;

		if (!managed)
			b.delete() ;
	}

	testInt8ArrayConstructorProperCopy (managed) {Buffer.instance.testTypedConstructorProperCopy(managed, Int8Array) ;}
	testUint8ArrayConstructorProperCopy (managed) {Buffer.instance.testTypedConstructorProperCopy(managed, Uint8Array) ;}
	testUint8ClampedArrayConstructorProperCopy (managed) {Buffer.instance.testTypedConstructorProperCopy(managed, Uint8ClampedArray) ;}
	testInt16ArrayConstructorProperCopy (managed) {Buffer.instance.testTypedConstructorProperCopy(managed, Int16Array) ;}
	testUint16ArrayConstructorProperCopy (managed) {Buffer.instance.testTypedConstructorProperCopy(managed, Uint16Array) ;}
	testInt32ArrayConstructorProperCopy (managed) {Buffer.instance.testTypedConstructorProperCopy(managed, Int32Array) ;}
	testUint32ArrayConstructorProperCopy (managed) {Buffer.instance.testTypedConstructorProperCopy(managed, Uint32Array) ;}
	testFloat32ArrayConstructorProperCopy (managed) {Buffer.instance.testTypedConstructorProperCopy(managed, Float32Array) ;}
	testFloat64ArrayConstructorProperCopy (managed) {Buffer.instance.testTypedConstructorProperCopy(managed, Float64Array) ;}

	testBigTypedConstructorProperCopy (managed, typedConstructor)
	{
		const a = new typedConstructor ([1n, 2n]) ;
		const ctor = Buffer.instance.getBufferConstructor(managed) ;
		const b = new ctor (a) ;

		const v = new Uint8Array (a.buffer) ;
		v[0] = 5 ;
		nkDebug.TestUtils.check(b.getData()[0] != v[0]) ;

		if (!managed)
			b.delete() ;
	}

	testBigInt64ArrayConstructorProperCopy (managed) {Buffer.instance.testBigTypedConstructorProperCopy(managed, BigInt64Array) ;}
	testBigUint64ArrayConstructorProperCopy (managed) {Buffer.instance.testBigTypedConstructorProperCopy(managed, BigUint64Array) ;}

	// Getters
	testEmpty (managed)
	{
		const ctor = Buffer.instance.getBufferConstructor(managed) ;

		const b = new ctor () ;
		nkDebug.TestUtils.check(b.empty(), "Not empty while it should") ;
		
		const c = new ctor (4) ;
		nkDebug.TestUtils.check(!c.empty(), "Empty while it should not") ;

		if (!managed)
		{
			b.delete() ;
			c.delete() ;
		}
	}

	testFront (managed)
	{
		const ctor = Buffer.instance.getBufferConstructor(managed) ;
		const b = new ctor (new Uint8Array ([1, 5, 8])) ;

		nkDebug.TestUtils.check(b.front() == 1) ;

		if (!managed)
			b.delete() ;
	}

	testBack (managed)
	{
		const ctor = Buffer.instance.getBufferConstructor(managed) ;
		const b = new ctor (new Uint8Array ([1, 5, 8])) ;

		nkDebug.TestUtils.check(b.back() == 8) ;

		if (!managed)
			b.delete() ;
	}

	// Management
	testClear (managed)
	{
		const ctor = Buffer.instance.getBufferConstructor(managed) ;
		const b = new ctor (new Uint8Array ([1, 5, 8])) ;

		b.clear() ;
		nkDebug.TestUtils.check(b.empty()) ;
		nkDebug.TestUtils.check(b.getData() == null) ;

		if (!managed)
			b.delete() ;
	}

	testResize (managed)
	{
		const ctor = Buffer.instance.getBufferConstructor(managed) ;
		const b = new ctor (new Uint8Array ([1, 5, 8])) ;

		b.resize(5) ;
		nkDebug.TestUtils.check(b.getSize() == 5) ;
		nkDebug.TestUtils.check(b.getData()[0] == 1) ;
		nkDebug.TestUtils.check(b.getData()[1] == 5) ;
		nkDebug.TestUtils.check(b.getData()[2] == 8) ;

		if (!managed)
			b.delete() ;
	}

	testAppend (managed)
	{
		const ctor = Buffer.instance.getBufferConstructor(managed) ;
		const b = new ctor (new Uint8Array ([1, 5, 8])) ;

		b.append(12) ;
		nkDebug.TestUtils.check(b.getSize() == 4) ;
		nkDebug.TestUtils.check(b.getData()[0] == 1) ;
		nkDebug.TestUtils.check(b.getData()[1] == 5) ;
		nkDebug.TestUtils.check(b.getData()[2] == 8) ;
		nkDebug.TestUtils.check(b.getData()[3] == 12) ;

		if (!managed)
			b.delete() ;
	}

	testErase (managed)
	{
		const ctor = Buffer.instance.getBufferConstructor(managed) ;
		const b = new ctor (new Uint8Array ([1, 5, 8, 4, 5])) ;

		b.erase(1) ;
		nkDebug.TestUtils.check(b.getSize() == 4, "Bad size erase 1") ;
		nkDebug.TestUtils.check(b.getData()[0] == 1, "Bad data erase 1") ;
		nkDebug.TestUtils.check(b.getData()[1] == 8, "Bad data erase 1") ;
		nkDebug.TestUtils.check(b.getData()[2] == 4, "Bad data erase 1") ;
		nkDebug.TestUtils.check(b.getData()[3] == 5, "Bad data erase 1") ;
		
		b.erase(1, 2) ;
		nkDebug.TestUtils.check(b.getSize() == 2, "Bad size erase 2") ;
		nkDebug.TestUtils.check(b.getData()[0] == 1), "Bad data erase 2" ;
		nkDebug.TestUtils.check(b.getData()[1] == 5), "Bad data erase 2" ;

		if (!managed)
			b.delete() ;
	}

	// Operators
	testAssignOperator (managed0, managed1)
	{
		const ctor0 = Buffer.instance.getBufferConstructor(managed0) ;
		const b0 = new ctor0 (new Uint8Array ([1, 2, 3])) ;

		const ctor1 = Buffer.instance.getBufferConstructor(managed1) ;
		const b1 = new ctor1 () ;
		b1.assign(b0) ;

		nkDebug.TestUtils.check(b0.getSize() == b1.getSize(), "Wrong copy size") ;

		for (let i = 0 ; i < b0.getSize() ; ++i)
		{
			nkDebug.TestUtils.check(b0.getData()[i] == b1.getData()[i], "Wrong copy value") ;
			b0.getData()[i] = -1 ;
			nkDebug.TestUtils.check(b0.getData()[i] != b1.getData()[i], "Data actually not copied") ;
		}

		if (!managed0)
			b0.delete() ;

		if (!managed1)
			b1.delete() ;
	}

	nkTests =
	{
		// Constructors
		DefaultConstructorUnmanaged : function () {Buffer.instance.testDefaultConstructor(false) ;},
		DefaultConstructorManaged : function () {Buffer.instance.testDefaultConstructor(true) ;},
		CopyConstructorUnmanaged : function () {Buffer.instance.testCopyConstructor(false, false) ;},
		CopyConstructorUnmanagedManaged : function () {Buffer.instance.testCopyConstructor(false, true) ;},
		CopyConstructorManagedUnmanaged : function () {Buffer.instance.testCopyConstructor(true, false) ;},
		CopyConstructorManaged : function () {Buffer.instance.testCopyConstructor(true, true) ;},
		SizeConstructorUnmanaged : function () {Buffer.instance.testSizeConstructor(false) ;},
		SizeConstructorManaged : function () {Buffer.instance.testSizeConstructor(true) ;},
		ArrayBufferConstructorUnmanaged : function () {Buffer.instance.testArrayBufferConstructor(false) ;},
		ArrayBufferConstructorManaged : function () {Buffer.instance.testArrayBufferConstructor(true) ;},
		Int8ArrayConstructorUnmanaged : function () {Buffer.instance.testInt8ArrayConstructor(false) ;},
		Int8ArrayConstructorManaged : function () {Buffer.instance.testInt8ArrayConstructor(true) ;},
		Uint8ArrayConstructorUnmanaged : function () {Buffer.instance.testUint8ArrayConstructor(false) ;},
		Uint8ArrayConstructorManaged : function () {Buffer.instance.testUint8ArrayConstructor(true) ;},
		Uint8ClampedArrayConstructorUnmanaged : function () {Buffer.instance.testUint8ArrayConstructor(false) ;},
		Uint8ClampedArrayConstructorManaged : function () {Buffer.instance.testUint8ArrayConstructor(true) ;},
		Int16ArrayConstructorUnmanaged : function () {Buffer.instance.testInt16ArrayConstructor(false) ;},
		Int16ArrayConstructorManaged : function () {Buffer.instance.testInt16ArrayConstructor(true) ;},
		Uint16ArrayConstructorUnmanaged : function () {Buffer.instance.testUint16ArrayConstructor(false) ;},
		Uint16ArrayConstructorManaged : function () {Buffer.instance.testUint16ArrayConstructor(true) ;},
		Int32ArrayConstructorUnmanaged : function () {Buffer.instance.testInt32ArrayConstructor(false) ;},
		Int32ArrayConstructorManaged : function () {Buffer.instance.testInt32ArrayConstructor(true) ;},
		Uint32ArrayConstructorUnmanaged : function () {Buffer.instance.testUint32ArrayConstructor(false) ;},
		Uint32ArrayConstructorManaged : function () {Buffer.instance.testUint32ArrayConstructor(true) ;},
		Float32ArrayConstructorUnmanaged : function () {Buffer.instance.testFloat32ArrayConstructor(false) ;},
		Float32ArrayConstructorManaged : function () {Buffer.instance.testFloat32ArrayConstructor(true) ;},
		Float64ArrayConstructorUnmanaged : function () {Buffer.instance.testFloat64ArrayConstructor(false) ;},
		Float64ArrayConstructorManaged : function () {Buffer.instance.testFloat64ArrayConstructor(true) ;},
		BigInt64ArrayConstructorUnmanaged : function () {Buffer.instance.testBigInt64ArrayConstructor(false) ;},
		BigInt64ArrayConstructorManaged : function () {Buffer.instance.testBigInt64ArrayConstructor(true) ;},
		BigUint64ArrayConstructorUnmanaged : function () {Buffer.instance.testBigUint64ArrayConstructor(false) ;},
		BigUint64ArrayConstructorManaged : function () {Buffer.instance.testBigUint64ArrayConstructor(true) ;},
		ArrayBufferConstructorProperCopyUnmanaged : function () {Buffer.instance.testArrayBufferConstructorProperCopy(false) ;},
		ArrayBufferConstructorProperCopyManaged : function () {Buffer.instance.testArrayBufferConstructorProperCopy(true) ;},
		Int8ArrayConstructorProperCopyUnmanaged : function () {Buffer.instance.testInt8ArrayConstructorProperCopy(false) ;},
		Int8ArrayConstructorProperCopyManaged : function () {Buffer.instance.testInt8ArrayConstructorProperCopy(true) ;},
		Uint8ArrayConstructorProperCopyUnmanaged : function () {Buffer.instance.testUint8ArrayConstructorProperCopy(false) ;},
		Uint8ArrayConstructorProperCopyManaged : function () {Buffer.instance.testUint8ArrayConstructorProperCopy(true) ;},
		Uint8ClampedArrayConstructorProperCopyUnmanaged : function () {Buffer.instance.testUint8ClampedArrayConstructorProperCopy(false) ;},
		Uint8ClampedArrayConstructorProperCopyManaged : function () {Buffer.instance.testUint8ClampedArrayConstructorProperCopy(true) ;},
		Int16ArrayConstructorProperCopyUnmanaged : function () {Buffer.instance.testInt16ArrayConstructorProperCopy(false) ;},
		Int16ArrayConstructorProperCopyManaged : function () {Buffer.instance.testInt16ArrayConstructorProperCopy(true) ;},
		Uint16ArrayConstructorProperCopyUnmanaged : function () {Buffer.instance.testUint16ArrayConstructorProperCopy(false) ;},
		Uint16ArrayConstructorProperCopyManaged : function () {Buffer.instance.testUint16ArrayConstructorProperCopy(true) ;},
		Int32ArrayConstructorProperCopyUnmanaged : function () {Buffer.instance.testInt32ArrayConstructorProperCopy(false) ;},
		Int32ArrayConstructorProperCopyManaged : function (){Buffer.instance.testInt32ArrayConstructorProperCopy(true) ;},
		Uint32ArrayConstructorProperCopyUnmanaged : function () {Buffer.instance.testUint32ArrayConstructorProperCopy(false) ;},
		Uint32ArrayConstructorProperCopyManaged : function () {Buffer.instance.testUint32ArrayConstructorProperCopy(true) ;},
		Float32ArrayConstructorProperCopyUnmanaged : function () {Buffer.instance.testFloat32ArrayConstructorProperCopy(false) ;},
		Float32ArrayConstructorProperCopyManaged : function () {Buffer.instance.testFloat32ArrayConstructorProperCopy(true) ;},
		Float64ArrayConstructorProperCopyUnmanaged : function () {Buffer.instance.testFloat64ArrayConstructorProperCopy(false) ;},
		Float64ArrayConstructorProperCopyManaged : function () {Buffer.instance.testFloat64ArrayConstructorProperCopy(true) ;},
		BigInt64ArrayConstructorProperCopyUnmanaged : function () {Buffer.instance.testBigInt64ArrayConstructorProperCopy(false) ;},
		BigInt64ArrayConstructorProperCopyManaged : function () {Buffer.instance.testBigInt64ArrayConstructorProperCopy(true) ;},
		BigUint64ArrayConstructorProperCopyUnmanaged : function () {Buffer.instance.testBigUint64ArrayConstructorProperCopy(false) ;},
		BigUint64ArrayConstructorProperCopyManaged : function () {Buffer.instance.testBigUint64ArrayConstructorProperCopy(true) ;},

		// Getters
		EmptyUnmanaged : function () {Buffer.instance.testEmpty(false) ;},
		EmptyManaged : function () {Buffer.instance.testEmpty(true) ;},
		FrontUnmanaged : function () {Buffer.instance.testFront(false) ;},
		FrontManaged : function () {Buffer.instance.testFront(true) ;},
		BackUnmanaged : function () {Buffer.instance.testBack(false) ;},
		BackManaged : function () {Buffer.instance.testBack(true) ;},

		// Management
		ClearUnmanaged : function () {Buffer.instance.testClear(false) ;},
		ClearManaged : function () {Buffer.instance.testClear(true) ;},
		ResizeUnmanaged : function () {Buffer.instance.testResize(false) ;},
		ResizeManaged : function () {Buffer.instance.testResize(true) ;},
		AppendUnmanaged : function () {Buffer.instance.testAppend(false) ;},
		AppendManaged : function () {Buffer.instance.testAppend(true) ;},
		EraseUnmanaged : function () {Buffer.instance.testErase(false) ;},
		EraseManaged : function () {Buffer.instance.testErase(true) ;},

		// Operators
		AssignOperatorUnmanaged : function () {Buffer.instance.testAssignOperator(false, false) ;},
		AssignOperatorUnmanagedManaged : function () {Buffer.instance.testAssignOperator(false, true) ;},
		AssignOperatorManagedUnmanaged : function () {Buffer.instance.testAssignOperator(true, false) ;},
		AssignOperatorManaged : function () {Buffer.instance.testAssignOperator(true, true) ;},
	}
}